﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using ReplayDataFile;

namespace View.Replay
{
   public delegate void SliderPostionChangedEventHandler(object setter, TimeSegment timeSeg,DateTime time,bool isDraging);
   public enum SliderType
   {
       Block,
       TimeRange
   }
    public class ReplayProgressBar : UserControl
    {
        // Fields
        private IContainer components = null;
        private bool isDragSlider;
        private bool isShowTimeTipOnMouseMove;
        private Font mouseMoveTimeStrFont;
        private Point mousePos;
        private int showTimeTipCount;

        // Events
        public event SliderPostionChangedEventHandler SliderPositionChanged;

        // Methods
        public ReplayProgressBar()
        {
            this.InitializeComponent();
            base.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            base.SetStyle(ControlStyles.EnableNotifyMessage, true);
            this.TimeSegmentList = new TimeSegmentList();
            this.CachedTimeSegmentList = new TimeSegmentList();
            this.SliderColor = Color.DarkGray;
            this.ForeColor = Color.LightGray;
            this.CachedDataColor = Color.DarkGray;
            this.TextColor = Color.Blue;
            this.BarBorderColor = Color.Black;
            this.TipTimeColor = Color.Black;
            this.SliderType = SliderType.Block;
            this.SliderSize = new Size(10, 15);
            this.LeftBlank = this.RightBlank = 20;
            this.TopBlank = this.BottomBlank = 5;
            this.mouseMoveTimeStrFont = new Font("宋体", 9f, FontStyle.Bold);
            this.TipTimeFormat = "HH:mm:ss";
            this.IsDrawCacheBar = false;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (this.components != null))
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void DrawDataSegmentBar(Graphics g, TimeSegmentList segmentList, Color color, Rectangle barRect, string text)
        {
            TimeSpan ts = new TimeSpan();
            TimeSegment segment = null;
            Brush brush = new SolidBrush(color);
            foreach (TimeSegment segment2 in segmentList)
            {
                if (segment != null)
                {
                    TimeSpan span2 = (TimeSpan)(segment2.BeginTime - segment.EndTime);
                    if (span2.Ticks > 0L)
                    {
                        ts += span2;
                    }
                }
                TimeSpan length = segment2.Length;
                int num = this.TimeSpan2XPos(ts);
                int width = this.TimeSpan2XPos(length) + 1;
                if (num >= barRect.Width)
                {
                    break;
                }
                if ((segment2.BeginRecordNo >= 0L) && (segment2.EndRecordNo >= 0L))
                {
                    Rectangle rect = new Rectangle(barRect.X + num, barRect.Y, width, barRect.Height);
                    rect.Intersect(barRect);
                    g.FillRectangle(brush, rect);
                }
                ts += length;
                segment = segment2;
            }
            brush.Dispose();
            if (!string.IsNullOrEmpty(text))
            {
                StringFormat format = new StringFormat
                {
                    Alignment = StringAlignment.Center,
                    LineAlignment = StringAlignment.Center
                };
                brush = new SolidBrush(this.TextColor);
                g.DrawString(text, this.Font, brush, barRect, format);
                brush.Dispose();
            }
            Pen pen = new Pen(this.BarBorderColor);
            g.DrawRectangle(pen, barRect);
            pen.Dispose();
        }

        private void DrawMouseMoveTipTime(Graphics g)
        {
            if (this.isShowTimeTipOnMouseMove)
            {
                DateTime posDateTime;
                Rectangle barRectangle = this.GetBarRectangle();
                Color tipTimeColor = this.TipTimeColor;
                if (this.isDragSlider)
                {
                    posDateTime = this.GetPosDateTime(this.GetSliderXPos());
                }
                else
                {
                    if (!barRectangle.Contains(this.mousePos))
                    {
                        return;
                    }
                    posDateTime = this.GetPosDateTime(this.mousePos.X - barRectangle.X);
                    Pen pen = new Pen(tipTimeColor);
                    g.DrawLine(pen, this.mousePos.X, barRectangle.Y, this.mousePos.X, barRectangle.Bottom);
                    pen.Dispose();
                }
                string text = posDateTime.ToString(this.TipTimeFormat);
                SizeF ef = g.MeasureString(text, this.mouseMoveTimeStrFont);
                float x = this.mousePos.X + 5;
                if ((x + ef.Width) > barRectangle.Right)
                {
                    x = (this.mousePos.X - ef.Width) - 5f;
                }
                float y = (barRectangle.Y + (barRectangle.Height / 2)) - (ef.Height / 2f);
                Brush brush = new SolidBrush(tipTimeColor);
                g.DrawString(text, this.mouseMoveTimeStrFont, brush, x, y);
                brush.Dispose();
            }
        }

        private void DrawSlider(Graphics g)
        {
            Rectangle sliderRectangle;
            if (this.SliderType == SliderType.Block)
            {
                sliderRectangle = this.GetSliderRectangle();
                g.FillRectangle(new SolidBrush(this.SliderColor), sliderRectangle);
                g.DrawLine(Pens.White, sliderRectangle.Location.X, sliderRectangle.Y, sliderRectangle.Right, sliderRectangle.Y);
                g.DrawLine(Pens.White, sliderRectangle.Location.X, sliderRectangle.Y, sliderRectangle.X, sliderRectangle.Bottom);
                g.DrawLine(Pens.Black, sliderRectangle.Right, sliderRectangle.Y, sliderRectangle.Right, sliderRectangle.Bottom - 1);
                g.DrawLine(Pens.Black, sliderRectangle.Location.X, sliderRectangle.Bottom - 1, sliderRectangle.Right, sliderRectangle.Bottom - 1);
            }
            else if (this.SliderType == SliderType.TimeRange)
            {
                sliderRectangle = this.GetSliderRectangle();
                g.FillRectangle(new SolidBrush(this.SliderColor), sliderRectangle);
            }
        }

        private void FillBackground(Graphics g)
        {
            SolidBrush brush = new SolidBrush(this.BackColor);
            g.FillRectangle(brush, this.DisplayRectangle);
            brush.Dispose();
        }

        private Rectangle GetBarRectangle()
        {
            Rectangle rectangle = new Rectangle
            {
                X = this.DisplayRectangle.X + this.LeftBlank,
                Width = (this.DisplayRectangle.Width - this.LeftBlank) - this.RightBlank,
                Y = this.DisplayRectangle.Y + this.TopBlank,
                Height = (this.DisplayRectangle.Height - this.TopBlank) - this.BottomBlank
            };
            if (rectangle.Height <= 0)
            {
                rectangle.Height = 5;
            }
            if (rectangle.Width < 10)
            {
                rectangle.Width = 10;
            }
            return rectangle;
        }

        private Rectangle GetCacheBarRectangle()
        {
            return this.GetBarRectangle();
        }

        public DateTime GetPosDateTime(int pos)
        {
            DateTime time;
            TimeSegment segment;
            this.GetPosDateTime(pos, out segment, out time);
            return time;
        }

        public void GetPosDateTime(int pos, out TimeSegment timeSeg, out DateTime time)
        {
            this.TimeSegmentList.Position2Time(this.XPos2TimeSpan(pos), out timeSeg, out time);
        }

        public DateTime GetSliderDateTime()
        {
            return this.GetPosDateTime(this.GetSliderXPos());
        }

        public TimeSpan GetSliderPosition()
        {
            return this.sliderPos;
        }

        private Rectangle GetSliderRectangle()
        {
            Rectangle barRectangle = this.GetBarRectangle();
            int sliderXPos = this.GetSliderXPos();
            if (this.SliderType == SliderType.Block)
            {
                return new Rectangle((barRectangle.X + sliderXPos) - (this.SliderSize.Width / 2), (barRectangle.Y + (barRectangle.Height / 2)) - (this.SliderSize.Height / 2), this.SliderSize.Width, this.SliderSize.Height);
            }
            int width = this.TimeSpan2XPos(this.SliderTimeRangeLen);
            if (width < 2)
            {
                width = 2;
            }
            return new Rectangle(barRectangle.X + sliderXPos, barRectangle.Y + 1, width, barRectangle.Height - 1);
        }

        private int GetSliderXPos()
        {
            return this.TimeSpan2XPos(this.sliderPos);
        }

        private void InitializeComponent()
        {
            base.SuspendLayout();
            //base.AutoScaleDimensions = new SizeF(6f, 12f);
            //base.AutoScaleMode = AutoScaleMode.Font;
            base.Name = "ReplayProgressBar";
            base.Size = new Size(0x27a, 50);
            base.Load += new EventHandler(this.ReplayProgressBar_Load);
            base.ResumeLayout(false);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if ((e.Button == MouseButtons.Left) && (this.MaxDisTimeLen.Ticks > 0L))
            {
                Rectangle sliderRectangle = this.GetSliderRectangle();
                if (sliderRectangle.Width < 10)
                {
                    int num = 10 - sliderRectangle.Width;
                    sliderRectangle.Width = 10;
                    sliderRectangle.X -= num / 2;
                }
                this.isDragSlider = sliderRectangle.Contains(e.X, e.Y);
                if (this.isDragSlider)
                {
                    base.Capture = true;
                    this.mousePos = new Point(e.X, e.Y);
                }
                else if (this.ClickSkipTimeLen.Ticks > 0L)
                {
                    Rectangle barRectangle = this.GetBarRectangle();
                    int num2 = (int)((this.ClickSkipTimeLen.Ticks * barRectangle.Width) / this.MaxDisTimeLen.Ticks);
                    int width = e.X - barRectangle.X;
                    if (width > barRectangle.Width)
                    {
                        width = barRectangle.Width;
                    }
                    if (width < 0)
                    {
                        width = 0;
                    }
                    int sliderXPos = this.GetSliderXPos();
                    if (System.Windows.Forms.Control.ModifierKeys == Keys.Control)
                    {
                        if (width > sliderXPos)
                        {
                            sliderXPos += num2;
                            if (sliderXPos > width)
                            {
                                sliderXPos = width;
                            }
                        }
                        else
                        {
                            sliderXPos -= num2;
                            if (sliderXPos < width)
                            {
                                sliderXPos = width;
                            }
                        }
                    }
                    else
                    {
                        sliderXPos = width;
                    }
                    this.SetSliderPosition(this, this.XPos2TimeSpan(sliderXPos), false);
                    base.Invalidate();
                }
                base.OnMouseDown(e);
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            this.isShowTimeTipOnMouseMove = false;
            this.showTimeTipCount = 0;
            base.Invalidate();
            base.OnMouseLeave(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            this.showTimeTipCount = 0;
            this.isShowTimeTipOnMouseMove = true;
            Rectangle sliderRectangle = this.GetSliderRectangle();
            Rectangle barRectangle = this.GetBarRectangle();
            if (sliderRectangle.Width < 10)
            {
                int num = 10 - sliderRectangle.Width;
                sliderRectangle.Width = 10;
                sliderRectangle.X -= num / 2;
            }
            this.Cursor = sliderRectangle.Contains(e.X, e.Y) ? Cursors.Hand : (this.Cursor = Cursors.Arrow);
            if (this.isDragSlider)
            {
                int num2 = e.X - this.mousePos.X;
                int pos = this.GetSliderXPos() + num2;
                if (pos < 0)
                {
                    pos = 0;
                }
                if (pos > barRectangle.Width)
                {
                    pos = barRectangle.Width;
                }
                this.SetSliderPosition(this, this.XPos2TimeSpan(pos), true);
            }
            this.mousePos = new Point(e.X, e.Y);
            base.Invalidate();
            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.isDragSlider)
                {
                    base.Capture = false;
                    this.isDragSlider = false;
                    this.SetSliderPosition(this, this.GetSliderPosition(), false);
                }
                base.OnMouseUp(e);
            }
        }

        protected override void OnNotifyMessage(Message m)
        {
            if (m.Msg != 20)
            {
                base.OnNotifyMessage(m);
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            this.FillBackground(g);
            this.DrawDataSegmentBar(g, this.TimeSegmentList, this.ForeColor, this.GetBarRectangle(), this.Text);
            if (this.IsDrawCacheBar)
            {
                this.DrawDataSegmentBar(g, this.CachedTimeSegmentList, this.CachedDataColor, this.GetCacheBarRectangle(), "");
            }
            this.DrawSlider(g);
            this.DrawMouseMoveTipTime(g);
            base.OnPaint(e);
        }

        private void ReplayProgressBar_Load(object sender, EventArgs e)
        {
            this.TipTimeColor = Color.Black;
            if (this.MaxDisTimeLen.Ticks == 0L)
            {
                this.MaxDisTimeLen = new TimeSpan(1, 0, 0);
            }
            this.ClickSkipTimeLen = new TimeSpan(this.MaxDisTimeLen.Ticks / 10L);
            Timer timer = new Timer
            {
                Interval = 200
            };
            timer.Tick += new EventHandler(this.timer_Tick);
            timer.Start();
        }

        public void SetSliderPosition(object setter, TimeSpan sliderPos)
        {
            this.SetSliderPosition(setter, sliderPos, false);
        }

        public void SetSliderPosition(object setter, TimeSpan sliderPos, bool isDraging)
        {
            if (sliderPos > this.MaxDisTimeLen)
            {
                sliderPos = this.MaxDisTimeLen;
            }
            this.sliderPos = sliderPos;
            if (this.SliderPositionChanged != null)
            {
                TimeSegment segment;
                DateTime time;
                this.TimeSegmentList.Position2Time(this.sliderPos, out segment, out time);
                this.SliderPositionChanged(setter, segment, time, isDraging);
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (this.isShowTimeTipOnMouseMove && (this.showTimeTipCount++ > 20))
            {
                this.isShowTimeTipOnMouseMove = false;
                base.Invalidate();
            }
        }

        private int TimeSpan2XPos(TimeSpan ts)
        {
            TimeSpan maxDisTimeLen = this.MaxDisTimeLen;
            Rectangle barRectangle = this.GetBarRectangle();
            if (maxDisTimeLen.Ticks <= 0L)
            {
                return 0;
            }
            return (int)Math.Round((double)((((double)ts.Ticks) / ((double)maxDisTimeLen.Ticks)) * barRectangle.Width));
        }

        private TimeSpan XPos2TimeSpan(int pos)
        {
            TimeSpan maxDisTimeLen = this.MaxDisTimeLen;
            Rectangle barRectangle = this.GetBarRectangle();
            return new TimeSpan((pos * maxDisTimeLen.Ticks) / ((long)barRectangle.Width));
        }

        // Properties
        public Color BarBorderColor { get; set; }

        public int BottomBlank { get; set; }

        public Color CachedDataColor { get; set; }

        public TimeSegmentList CachedTimeSegmentList { get; set; }

        public TimeSpan ClickSkipTimeLen { get; set; }

        public bool IsDrawCacheBar { get; set; }

        public int LeftBlank { get; set; }

        public TimeSpan MaxDisTimeLen { get; set; }

        public int RightBlank { get; set; }

        public Color SliderColor { get; set; }

        private TimeSpan sliderPos { get; set; }

        public Size SliderSize { get; set; }

        public TimeSpan SliderTimeRangeLen { get; set; }

        public SliderType SliderType { get; set; }

        public Color TextColor { get; set; }

        public TimeSegmentList TimeSegmentList { get; set; }

        public Color TipTimeColor { get; set; }

        public string TipTimeFormat { get; set; }

        public int TopBlank { get; set; }
    }




}
